﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UseCase.cs" company="">
//   
// </copyright>
// <summary>
//   UseCase represents case of ui usage by actor
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using Libium.Core;

namespace Libium.UseCases
{
    using System;
    using System.Collections.Generic;

    using Libium.Validation;

    /// <summary>
    /// UseCase represents case of ui usage by actor
    /// </summary>
    /// <includesource>yes</includesource>
    public abstract partial class UseCase : ViewBindable, IUseCase
    {
        #region Fields

        /// <summary>
        ///   The _command handlers.
        /// </summary>
        private readonly Dictionary<Guid, CommandHandlerInfo> _commandHandlers =
            new Dictionary<Guid, CommandHandlerInfo>();

        /// <summary>
        ///   The _commands.
        /// </summary>
        private readonly List<ICommand> _commands = new List<ICommand>();

        /// <summary>
        ///   The _errors.
        /// </summary>
        private readonly List<IError> _errors = new List<IError>();

        /// <summary>
        ///   The _hints.
        /// </summary>
        private readonly List<IHint> _hints = new List<IHint>();

        /// <summary>
        ///   The _validation records.
        /// </summary>
        private readonly List<ValidationRecord> _validationRecords = new List<ValidationRecord>();

        /// <summary>
        ///   The _warnings.
        /// </summary>
        private readonly List<IWarning> _warnings = new List<IWarning>();

        /// <summary>
        ///   The _active.
        /// </summary>
        private bool _active;

        /// <summary>
        ///   The _empty.
        /// </summary>
        private bool _empty;

        /// <summary>
        ///   The _modified.
        /// </summary>
        private bool _modified;

        /// <summary>
        ///   The _readonly.
        /// </summary>
        private bool _readonly;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="service">The service.</param>
        protected UseCase(ICompoundUseCase parent, IUseCaseInstanceService service)
        {
            Parent = parent;
            if (Parent != null)
            {
                // TODO Add unsubscribe on unavailable
                Parent.EnabledChanged += uc => OnParentEnabledChanged();
                Parent.ReadonlyChanged += uc => OnParentReadonlyChanged();
            }
            Service = service;
        }

        #endregion

        #region Public Events

        /// <summary>
        ///   The active changed.
        /// </summary>
        public event Action<IUseCase> ActiveChanged;

        /// <summary>
        /// The empty changed.
        /// </summary>
        public event Action<IUseCase> EmptyChanged;

        /// <summary>
        ///   The modified changed.
        /// </summary>
        public event Action<IUseCase> ModifiedChanged;

        /// <summary>
        ///   The readonly changed.
        /// </summary>
        public event Action<IUseCase> ReadonlyChanged;

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets or sets a value indicating whether active.
        /// </summary>
        public virtual bool Active
        {
            get
            {
                return _active;
            }

            set
            {
                if (_active == value)
                {
                    return;
                }

                _active = value;
                OnActiveChanged();
            }
        }

        /// <summary>
        ///   Gets or sets the description.
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        ///   Gets or sets a value indicating whether empty.
        /// </summary>
        public virtual bool Empty
        {
            get
            {
                return _empty;
            }

            protected set
            {
                if (_empty == value)
                {
                    return;
                }

                _empty = value;
                OnEmptyChanged();
            }
        }

        /// <summary>
        ///   Gets or sets a value indicating whether enabled.
        /// </summary>
        public override bool Enabled
        {
            get
            {
                return (Parent == null || Parent.Enabled) && base.Enabled;
            }

            set
            {
                if (_enabled == value)
                {
                    return;
                }

                _enabled = value;
                if (Parent != null && !Parent.Enabled)
                {
                    return;
                }

                OnEnabledChanged();
            }
        }

        /// <summary>
        ///   Gets or sets the help uri.
        /// </summary>
        public string HelpUri { get; set; }

        /// <summary>
        ///   Gets or sets a value indicating whether modified.
        /// </summary>
        public virtual bool Modified
        {
            get
            {
                return _modified;
            }

            protected set
            {
                if (_modified == value)
                {
                    return;
                }

                _modified = value;
                OnModifiedChanged();
            }
        }

        /// <summary>
        ///   Gets or sets the name.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        ///   Gets or sets the parent.
        /// </summary>
        public ICompoundUseCase Parent { get; set; }

        /// <summary>
        ///   Gets or sets a value indicating whether read only.
        /// </summary>
        public virtual bool ReadOnly
        {
            get
            {
                return (Parent != null && Parent.ReadOnly) || _readonly;
            }

            set
            {
                if (_readonly == value)
                {
                    return;
                }

                _readonly = value;
                if (Parent != null && Parent.ReadOnly)
                {
                    return;
                }

                OnReadonlyChanged();
            }
        }

        /// <summary>
        ///   Gets the root.
        /// </summary>
        public ICompoundUseCase Root
        {
            get
            {
                return Parent == null ? ((ICompoundUseCase)this) : Parent.Root;
            }
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets the service.
        /// </summary>
        protected virtual IUseCaseInstanceService Service { get; private set; }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        ///   The make empty.
        /// </summary>
        public virtual void MakeEmpty()
        {
        }

        #endregion

        #region Methods

        /// <summary>
        /// The execute modal use case.
        /// </summary>
        /// <param name="useCase">
        /// The use case. 
        /// </param>
        /// <returns>
        /// The <see cref="CommandDefinition"/> . 
        /// </returns>
        protected CommandDefinition ExecuteModalUseCase(IUseCase useCase)
        {
            return Service.ExecuteModalUseCase(useCase);
        }

        /// <summary>
        ///   The on active changed.
        /// </summary>
        protected virtual void OnActiveChanged()
        {
            if (ActiveChanged != null)
            {
                ActiveChanged(this);
            }
        }

        /// <summary>
        ///   The on empty changed.
        /// </summary>
        protected virtual void OnEmptyChanged()
        {
            if (EmptyChanged != null)
            {
                EmptyChanged(this);
            }
        }

        /// <summary>
        ///   The on modified changed.
        /// </summary>
        protected virtual void OnModifiedChanged()
        {
            if (ModifiedChanged != null)
            {
                ModifiedChanged(this);
            }
        }

        /// <summary>
        ///   The on readonly changed.
        /// </summary>
        protected virtual void OnReadonlyChanged()
        {
            if (ReadonlyChanged != null)
            {
                ReadonlyChanged(this);
            }
        }

        /// <summary>
        ///   The on parent enabled changed.
        /// </summary>
        private void OnParentEnabledChanged()
        {
            var previous = (!Parent.Enabled) && base.Enabled;
            var current = Parent.Enabled && base.Enabled;
            if (previous != current)
            {
                OnEnabledChanged();
            }
        }

        /// <summary>
        ///   The on parent readonly changed.
        /// </summary>
        private void OnParentReadonlyChanged()
        {
            var previous = (!Parent.ReadOnly) || _readonly;
            var current = Parent.ReadOnly || _readonly;
            if (previous != current)
            {
                OnReadonlyChanged();
            }
        }

        #endregion

        public virtual void ResetModified()
        {
            _modified = false;
        }

        public void Activate()
        {

        }

        public void Deactivate()
        {

        }

        public bool IsInitialized
        {
            get { throw new NotImplementedException(); }
        }

        public void Dispose()
        {
            throw new NotImplementedException();
        }

        public void Initialize()
        {
            throw new NotImplementedException();
        }

        private bool _isStarted;
        private bool _wasStopped;

        public event Action<IStartable> BeforeStart;
        public event Action<IStartable> AfterStart;
        public event Action<IStartable> BeforeStop;
        public event Action<IStartable> AfterStop;

        public bool IsStarted
        {
            get { return _isStarted; }
        }

        public virtual void OnBeforeStart(bool isRestarting)
        {
        }

        public virtual void OnAfterStart(bool isRestarting)
        {
        }

        public void Start()
        {
            OnBeforeStart(_wasStopped);
            if (BeforeStart != null)
            {
                BeforeStart(this);
            }
            _isStarted = true;
            OnAfterStart(_wasStopped);
            if (AfterStart != null)
            {
                AfterStart(this);
            }            
        }

        public virtual void OnBeforeStop()
        {
        }

        public virtual void OnAfterStop()
        {
        }

        public void Stop()
        {
            OnBeforeStop();
            if (BeforeStop != null)
            {
                BeforeStop(this);
            }
            _isStarted = false;
            OnAfterStop();
            if (AfterStop != null)
            {
                AfterStop(this);
            }            
        }

        private bool _isSuspended;

        public event Action<ISuspendable> BeforeSuspend;
        public event Action<ISuspendable> AfterSuspend;
        public event Action<ISuspendable> BeforeResume;
        public event Action<ISuspendable> AfterResume;

        public bool IsSuspended
        {
            get { return _isSuspended; }
        }

        public virtual void OnBeforeSuspend()
        {
        }

        public virtual void OnAfterSuspend()
        {
        }

        public void Suspend()
        {
            _isSuspended = true;
            //OnSuspend();
            if (AfterSuspend != null)
            {
                AfterSuspend(this);
            }
        }

        public void Resume()
        {
            _isSuspended = false;
            //OnResume();
            if (AfterResume != null)
            {
                AfterResume(this);
            }            
        }
    }
}